// ------------------------------------------------------------------------------------------
// Licensed by Interprise Solutions.
// http://www.InterpriseSolutions.com
// For details on this license please visit  the product homepage at the URL above.
// THE ABOVE NOTICE MUST REMAIN INTACT.
// ------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Collections;
using System.IO;
using System.ComponentModel;

namespace InterpriseSuiteEcommerceControls.Validators
{
    public class ValidationErrorEventArgs : EventArgs
    {
        private string _errorMessage = string.Empty;

        public ValidationErrorEventArgs(string errorMessage)
        {
            _errorMessage = errorMessage;
        }

        public string ErrorMessage
        {
            get { return _errorMessage; }
        }
    }

    public abstract class InputValidator : CompositeControl, IValidator
    {
        #region Variable Declaration

        private string _errorMessage = string.Empty;
        private bool _isValid = true;
        private InputValidator _nextChainedValidator = null;
        private bool _enableClientSideValidation = true;
        private bool _renderScript = true;

        public event EventHandler<ValidationErrorEventArgs> Error;
        public event CancelEventHandler Evaluate;

        #endregion

        #region Constructor

        protected InputValidator(string errorMessage) : this(errorMessage, null) { }


        /// <summary>
        /// InputValidator contructor.
        /// To ensure that we have a chaining validator behavior
        /// Let's make the succedding validator use decorator
        /// so that we can have successions of validators.
        /// Instead of creating another class that's solely reponsible
        /// for chaining...
        /// </summary>
        /// <param name="errorMessage">The error message to be displayed</param>
        /// <param name="next">The succeding validator...</param>
        protected InputValidator(string errorMessage, InputValidator next)
        {
            _errorMessage = errorMessage;
            _nextChainedValidator = next;
        }

        #endregion

        #region Properties

        public string ErrorMessage
        {
            get { return _errorMessage; }
            set { _errorMessage = value; }
        }

        public InputValidator Next
        {
            get { return _nextChainedValidator; }
        }

        public bool IsValid
        {
            get { return _isValid; }
            set { _isValid = value; }
        }

        public bool EnableClientSideValidation
        {
            get { return _enableClientSideValidation; }
            set { _enableClientSideValidation = value; }
        }

        public bool RenderScript
        {
            get { return _renderScript; }
            set { _renderScript = value; }
        }
        #endregion

        #region Methods

        public virtual void OnError(ValidationErrorEventArgs e)
        {
            if (null != Error)
            {
                Error(this, e);
            }
        }

        public void Validate()
        {
            foreach (InputValidator validator in GetChainedValidators())
            {
                IsValid = validator.DoEvaluate(); 

                if (!IsValid)
                {
                    OnError(new ValidationErrorEventArgs(validator.ErrorMessage));
                    break;
                }
            }
        }

        protected bool DoEvaluate()
        {
            CancelEventArgs e = new CancelEventArgs();
            OnEvaluate(e);
            if (e.Cancel) return true;

            return EvaluateIsValid();
        }

        protected void OnEvaluate(CancelEventArgs e)
        {
            if (null != Evaluate)
            {
                Evaluate(this, e);
            }
        }

        protected abstract bool EvaluateIsValid();

        protected override void OnInit(EventArgs e)
        {
            if (null != Page)
            {
                Page.Validators.Add(this);
            }

            base.OnInit(e);
        }

        protected virtual IEnumerable GetChainedValidators()
        {
            List<InputValidator> validators = new List<InputValidator>();

            InputValidator currentValidator = this;
            validators.Add(currentValidator);

            while (null != currentValidator)
            {
                currentValidator = currentValidator.Next;

                if (null != currentValidator)
                {
                    validators.Add(currentValidator);
                }
            }

            return validators;
        }

        protected override void OnUnload(EventArgs e)
        {
            if (null != Page)
            {
                Page.Validators.Remove(this);
            }

            base.OnUnload(e);
        }

        public abstract bool SupportsClientSideValidation { get;}

        protected virtual void RenderBeginScriptTag(HtmlTextWriter writer)
        {
            writer.WriteLine("<script type=\"text/javascript\" language=\"Javascript\" >");
        }

        protected virtual void RenderEndScriptTag(HtmlTextWriter writer)
        {
            writer.WriteLine("</script>");
        }

        protected override void Render(HtmlTextWriter writer)
        {
            
        }

        protected void RenderScriptContents(HtmlTextWriter writer)
        {
            RenderBeginAttachWindowOnLoadEventHandler(writer);
            RenderRegistration(writer);
            RenderEndAttachWindowOnLoadEventHandler(writer);
        }

        internal virtual void RenderRegistration(HtmlTextWriter writer)
        {
            writer.WriteLine();
            writer.Write(string.Format("ise.Validators.ValidationController.register({0});", this.RenderInitialization()));
            writer.WriteLine();
        }

        protected string RenderChainedValidatorInitialization()
        {
            InputValidator participatingValidator = FindNextChainedValidatorThatSupportsClientSideValidation(_nextChainedValidator);

            if (null != participatingValidator)
            {
                return participatingValidator.RenderInitialization();
            }
            return "null";
        }

        protected InputValidator FindNextChainedValidatorThatSupportsClientSideValidation(InputValidator nextValidator)
        {
            if (null != nextValidator)
            {
                if (nextValidator.SupportsClientSideValidation && nextValidator.EnableClientSideValidation)
                {
                    return nextValidator;
                }
                else
                {
                    return FindNextChainedValidatorThatSupportsClientSideValidation(nextValidator.Next);
                }
            }

            return null;
        }

        protected void RenderBeginAttachWindowOnLoadEventHandler(HtmlTextWriter writer)
        {
            writer.WriteLine("Event.observe(window, 'load', function() {");
        }

        protected void RenderEndAttachWindowOnLoadEventHandler(HtmlTextWriter writer)
        {
            writer.WriteLine("    });");
        }

        public virtual string RenderInitialization()
        {
            return "null";
        }

        #endregion
    }
}
